package util

import (
	"fmt"
	"net"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/fwhezfwhez/errorx"
	"github.com/shirou/gopsutil/process"
	"github.com/spf13/viper"
)

func ReadConfigFile(path string) (map[string]interface{}, error) {
	if !PathExists(path) {
		return nil, fmt.Errorf("路径[%v]不存在", path)
	}
	viper.SetConfigFile(path)
	err := viper.ReadInConfig()
	if nil != err {
		return nil, errorx.New(err)
	}
	allKeys := viper.AllKeys()

	allMaps := make(map[string]interface{}, len(allKeys))

	for _, key := range allKeys {
		allMaps[key] = viper.Get(key)
	}
	return allMaps, nil
}

// GetNow 获取当期日期和时间,格式:yyyy-MM-dd hh:mm:ss
func GetNow() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

// PathExists 判断文件夹是否存在
func PathExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

// ByteToHexStr byte数组转16进制字符串
func ByteToHexStr(prx bool, buff []byte) string {
	str := ""
	if buff == nil {
		return str
	}
	mLen := len(buff)
	if mLen == 0 {
		return str
	}
	p := ""
	if prx {
		p = "0x"
	}
	for i := 0; i < mLen; i++ {
		if i == mLen-1 {
			str += fmt.Sprintf("%v%02.2X", p, buff[i])
		} else {
			str += fmt.Sprintf("%v%02.2X,", p, buff[i])
		}
	}
	return str
}

// CheckFileIsExist 判断文件是否存在
func CheckFileIsExist(filename string) bool {
	var exist = true
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		exist = false
	}
	return exist
}

// Separator 路径分隔符
func Separator() string {
	return string(filepath.Separator)
}

// GetLocalIPV4 获取本地IPV4的IP地址
func GetLocalIPV4() ([]string, error) {
	addr, err := net.InterfaceAddrs()
	if err != nil {
		return nil, err
	}
	var ips []string
	for _, address := range addr {
		if ip, ok := address.(*net.IPNet); ok && !ip.IP.IsLoopback() {
			if ip.IP.To4() != nil {
				ips = append(ips, ip.IP.String())
			}
		}
	}
	return ips, nil
}

// CheckIP 检查IPV4的地址是否合法
func CheckIP(ip string) bool {
	addr := strings.Trim(ip, " ")
	regStr := `^(([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
	if match, _ := regexp.MatchString(regStr, addr); match {
		return true
	}
	return false
}

// StrIp2Byte 将IP
func StrIp2Byte(locationIp string) ([]byte, error) {
	result := CheckIP(locationIp)
	if !result {
		return nil, fmt.Errorf("错误的IP地址:[%v]", locationIp)
	}
	split := strings.Split(locationIp, ".")
	ips := make([]byte, 4)
	for i, v := range split {
		x, e := strconv.Atoi(v)
		if e != nil {
			return nil, fmt.Errorf("IP转化错误:[%v]", e)
		}
		ips[i] = byte(x)
	}
	return ips, nil
}

// CheckAppStarted : Check the application is already started
// appExecuteName  :	Need check application execute name
// return
//
//	bool  : true application is not started,otherwise application is started
//	error : If return false the error description error information
func CheckAppStarted(appExecuteName string) (bool, error) {
	curPid := os.Getpid()
	appProcessPids, err1 := GetProcessPid(appExecuteName)
	if err1 == nil {
		for _, v := range appProcessPids {
			if v != curPid {
				err1 := fmt.Errorf("找到了同名进程,但是PID不一样,找到的PID:%v,正确的PID:%v", v, curPid)
				return false, err1
			}
		}
	}

	name, _ := GetProcessName(curPid)
	if name != appExecuteName {
		err1 := fmt.Errorf("当前程序名称与被检查的程序名称不一致,被检测的可执行程序名称为[%v],当前程序名称为[%v]", appExecuteName, name)
		return false, err1
	}
	return true, nil
}

// GetProcessPid 通过进程名称获取进程ID
func GetProcessPid(name string) ([]int, error) {
	ids, err := process.Pids()
	if err != nil {
		return nil, err
	}
	var p []int
	name = strings.ToLower(name)
	for _, pid := range ids {
		pn, _ := process.NewProcess(pid)
		pName, _ := pn.Name()
		if name == strings.ToLower(pName) {
			i := int(pid)
			p = append(p, i)
		}
	}
	return p, nil
}

// GetProcessName 根据进程pid获取进程名称
func GetProcessName(pid int) (string, error) {
	ids, err := process.Pids()
	if err != nil {
		return "", err
	}

	for _, p := range ids {
		pd := int(p)
		if pd == pid {
			pn, _ := process.NewProcess(int32(pid))
			pName, _ := pn.Name()
			return pName, nil
		}
	}
	return "", fmt.Errorf("进程编号[%v]不存在", pid)
}

// StrCount 获取字符串中的字符个数
func StrCount(v string) int {
	runes := []rune(v)
	return len(runes)
}
